/**
 * @file allow: 允许某几个promise失败
 */
import {isArray} from './utils';

export interface Response {
    isError: boolean,
    data: any
}

export function extendsPromiseAllow () {
    // @ts-ignore
    Promise.allow = function(
        array: Array<Promise<any>>,
        whiteList: Array<number>
    ) {
        if (!isArray(array)) {
            return Promise.reject('has no params');
        }
        let length = array.length;
        if (length < 2) {
            return Promise.reject('should not use Promise.allow, this function require the length of params large than 1');
        }

        return new Promise((resolve, reject) => {
            const result: Array<Response> = [];
            let count: number = 0;

            const filter = (result: Array<Response>) => {
                if (result.every(item => item.isError)) {
                    return reject(result);
                }

                // 去重
                const list = Array.from(new Set(whiteList));
                const isPartSuccess = result.every((item, index) => {
                    if (list.indexOf(index) !== -1) {
                        return true;
                    } else {
                        return !item.isError;
                    }
                });
                const fn = isPartSuccess ? resolve : reject;
                fn(result);
            };

            const complete = (index: number, response: any, isError: boolean) => {
                count += 1;
                result[index] = {data: response, isError};
                if (count === length) {
                    if (isArray(whiteList) && whiteList.length > 0) {
                        filter(result);
                    } else {
                        let isSuccess = result.some(item => !item.isError);
                        const fn = isSuccess ? resolve : reject;
                        fn(result);
                    }
                }
            };

            for (let i = 0; i < length; i++) {
                const promise = array[i];
                promise
                    .then(data => {
                        complete(i, data, false);
                    })
                    .catch(e => {
                        complete(i, e, true);
                    });
            }
        });
    }
}